package gbase

import (
	"crypto/md5"
	"fmt"
	"math/rand"
	"os"
	"runtime/pprof"
	"slices"
	"sort"
	"strings"
	"time"

	jsoniter "github.com/json-iterator/go"
)

func Sn(len int) string {
	t := NewTime()
	return fmt.Sprintf("%s%d%s", t.Cb.Format("YmdHis"), t.Cb.Microsecond(), GetRandomString(len))
}

func GetRandomString(lens int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for range lens {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

// InArray 检查元素是否在切片中（泛型版本，支持任何可比较类型）
func InArray[T comparable](item T, arr []T) bool {
	return slices.Contains(arr, item)
}

func RandRatio[T TNum](percent, denominator T) bool {
	var randNum T
	// 生成一个0到denominator之间的随机数，对于浮点数，需要生成0到1之间的随机数再乘以denominator
	r := rand.Float64()
	randNum = T(r * float64(denominator))
	return randNum > 0 && percent >= randNum
}

func RandRangNum[T int | int64 | float64](min, max T) T {
	if min >= max || max == 0 {
		return max
	}

	switch any(min).(type) {
	case int:
		return T(rand.Intn(int(max)-int(min)+1) + int(min))
	case int64:
		return T(rand.Int63n(int64(max)-int64(min)+1) + int64(min))
	case float64:
		return T(rand.Float64()*float64(max-min) + float64(min))
	default:
		panic("unsupported type")
	}
}
func Password(len int, oriPwd string) (pwd string, salt string) {
	salt = GetRandomString(len)
	defaultPwd := "123456"
	if oriPwd != "" {
		defaultPwd = oriPwd
	}
	pwd = Md5([]byte(defaultPwd + salt))
	return pwd, salt
}

// Md5函数接受一个泛型参数T，T可以是[]byte或string类型
func Md5[T TByteOrStr](input T, upCase ...bool) string {
	var data []byte
	switch v := any(input).(type) {
	case []byte:
		data = v
	case string:
		data = []byte(v)
	}

	if len(upCase) > 0 && upCase[0] {
		return strings.ToUpper(fmt.Sprintf("%X", md5.Sum(data)))
	} else {
		return strings.ToLower(fmt.Sprintf("%x", md5.Sum(data)))
	}
}

func JsonStr(obj any) string {
	str, _ := jsoniter.MarshalToString(obj)
	return str
}

// 对切片进行排序，支持范型，可以是int、float、string等
func SortSlice[T TNum | ~string](arr []T, asc ...bool) []T {
	if len(arr) <= 1 {
		return arr
	}
	//标准库排序实现
	// 创建一个新的切片，避免修改原始切片
	result := make([]T, len(arr))
	copy(result, arr)

	// 使用sort包进行排序
	if len(asc) == 0 || asc[0] {
		slices.Sort(result)
	} else {
		sort.Slice(result, func(i, j int) bool {
			return result[i] > result[j]
		})
	}
	return result
}

// 不区分大小写的字符串比较器，用于treemap包和gbase.Map
func StringComparatorWithoutCase(a, b any) int {
	aStr := strings.ToLower(a.(string))
	bStr := strings.ToLower(b.(string))

	if aStr < bStr {
		return -1
	} else if aStr > bStr {
		return 1
	}
	return 0
}

// If 三元运算符，根据条件返回不同的值
// 用法: If(condition, trueValue, falseValue)
// 示例: If(isA, "A", "B") 如果 isA 为 true 返回 "A"，否则返回 "B"
func If[T any](condition bool, trueVal, falseVal T) T {
	if condition {
		return trueVal
	}
	return falseVal
}

// 性能分析
func StartCpuPprof(filename ...string) (cpuFile *os.File, err error) {
	// ===== 性能分析：开启 CPU profiling =====
	_filename := fmt.Sprintf("cpu_%s.prof", time.Now().Format("20060102_150405"))
	if len(filename) > 0 {
		_filename = filename[0]
	}
	cpuFile, err = os.Create(_filename)
	if err != nil {
		return nil, err
	}
	pprof.StartCPUProfile(cpuFile)
	return
}

func StopCpuPprof(file *os.File) {
	pprof.StopCPUProfile()
	file.Close()
}
